package fr.uvsq.isty.bdh.hchess.ranking;

import java.io.IOException;
import java.util.ArrayList;

/**
 * An Elo based collection of function, providing a non explosive
 * rating of players. The median of the rating will always be the default
 * rating.
 * @author Clement Bellot <clementbellot@gmail.com>
 */
public class RatingCalculator {
    private static final int ScoreDifferenceTenfold = 400;
    private static final int maxRatingChange = 32;
    public static int getDefaultRating(){
        return 1200;
    }
    /**
     * 
     * @param ratingP1
     * @param ratingP2	
     * @return The expected score according to ELO.
     */
    private static double expectedScore(int ratingP1,int ratingP2){
        return 1.0/(1.0+Math.pow(10,(ratingP2-ratingP1)/ScoreDifferenceTenfold));
    }
    /**
     * see http://en.wikipedia.org/wiki/Elo_rating_system#Theory
     * for explanations.
     * @param p1
     * @param p2
     * @param scoreP1 The actual player 1 score
     */
    private static void updateRatings(Player p1,Player p2, double scoreP1){
        double expectedScoreP1 = expectedScore(p1.getRating(),p2.getRating());
        int finalScoreChange = (int)(maxRatingChange*((double)scoreP1-expectedScoreP1));
        if(p1.getRating()<=100 && finalScoreChange<0){
            return;
        }
        if(p2.getRating()<=100 && finalScoreChange>0){
            return;
        }
        p1.setRating(p1.getRating()+finalScoreChange);
        p2.setRating(p2.getRating()-finalScoreChange);
    }
    /**
     * Update the given players rating.
     * @param winner
     * @param looser 
     */
    public static void updateRatingsWin(Player winner,Player looser){
        updateRatings(winner,looser,1.0);
    }
    /**
     * Update the given players rating after loading them.
     * @param winnerName
     * @param looserName 
     */
    public static void updateRatingsWin(String winnerName,String looserName){
        
    	//one name empty: do nothing
    	if(winnerName == null || looserName == null) 
        {return ;}
    	
    	Player winner;
        Player looser;
        ArrayList<Player> winList; 
        ArrayList<Player> losList;
        
        try {
			winList = Players.getInstance().getItemsWithFilter(winnerName);
			losList = Players.getInstance().getItemsWithFilter(looserName);
			
	        //if we don"t get on of the player, we exit
	        if( winList.size() <= 0 || losList.size() <= 0)
	        {return ;}
	        
	        winner = winList.get(0);
	        looser = losList.get(0);	        
	        	    	
	    	updateRatings(winner,looser,1.0);
	        
		} catch (IOException e) {			
			e.printStackTrace();
		}        

    }
    /**
     * Update the given players rating.
     * @param p1
     * @param p2 
     */
    public static void updateRatingsDraw(Player p1, Player p2){
        updateRatings(p1,p2,0.5);
    }
    
    /**
     * Update the given players rating after loading them.
     * @param p1Name player 1 name
     * @param p2Name player 2 name
     */
    public static void updateRatingsDraw(String p1Name, String p2Name){
    	//one name empty: do nothing
    	if(p1Name == null || p2Name == null) 
        {return ;}
    	
    	Player p1;
        Player p2;
        ArrayList<Player> p1List; 
        ArrayList<Player> p2List;
        
        try {
        	p1List = Players.getInstance().getItemsWithFilter(p1Name);
        	p2List = Players.getInstance().getItemsWithFilter(p2Name);
			
	        //if we don"t get on of the player, we exit
	        if( p1List.size() <= 0 || p2List.size() <= 0)
	        {return ;}
	        
	        p1 = p1List.get(0);
	        p2 = p2List.get(0);	        
	        	    	
	    	updateRatings(p1,p2,0.5);
	        
		} catch (IOException e) {			
			e.printStackTrace();
		} 
    }
    
}
